﻿#region License

// This file is part of Grawlix.
// 
// Grawlix is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// Grawlix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with Grawlix.  If not, see
// <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Drawing;
using System.Threading;
using C5;

namespace Grawlix.Services.Rendering
{
	/// <summary>
	/// A structure used to lay out a run of similar text.
	/// </summary>
	public struct TextRun : IEquatable<TextRun>
	{
		/// <summary>
		/// The font to render the text with.
		/// </summary>
		private IFontResource _font;

		/// <summary>
		/// The run of glyphs.
		/// </summary>
		private ArrayList<Glyph> _run;

		/// <summary>
		/// The color to tint the text.
		/// </summary>
		private Color _tint;

		/// <summary>
		/// Gets or sets the text font.
		/// </summary>
		/// <value>The font to render the text with.</value>
		public IFontResource Font
		{
			get { return _font; }
			set { _font = value; }
		}

		/// <summary>
		/// Gets the run of glyphs.
		/// </summary>
		/// <value>The run of glyphs, holding index and positioning
		/// information.</value>
		public IList<Glyph> Run
		{
			get
			{
				if (_run == null)
				{
					var run = new ArrayList<Glyph>();
					Interlocked.CompareExchange(ref _run, run, null);
				}
				return _run;
			}
		}

		/// <summary>
		/// Gets or sets the font color.
		/// </summary>
		/// <value>The color to tint the text.</value>
		public Color Tint
		{
			get { return _tint; }
			set { _tint = value; }
		}

		/// <summary>
		/// Indicates whether the current object is equal to another
		/// object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.
		/// </param>
		/// <returns>
		/// true if the current object is equal to the 
		/// <paramref name="other"/> parameter; otherwise, false.
		/// </returns>
		public bool Equals(TextRun other)
		{
			return other._font.Equals(_font) && other.Run.Equals(Run) &&
			       other._tint.Equals(_tint);
		}

		/// <summary>
		/// Indicates whether this instance and a specified object are
		/// equal.
		/// </summary>
		/// <param name="obj">Another object to compare to.</param>
		/// <returns>
		/// true if <paramref name="obj"/> and this instance are the
		/// same type and represent the same value; otherwise, false.
		/// </returns>
		public override bool Equals(object obj)
		{
			if (obj.GetType() != typeof(TextRun))
				return false;
			return Equals((TextRun)obj);
		}

		/// <summary>
		/// Returns the hash code for this instance.
		/// </summary>
		/// <returns>
		/// A 32-bit signed integer that is the hash code for this
		/// instance.
		/// </returns>
		public override int GetHashCode()
		{
			unchecked
			{
				int result = (_font != null ? _font.GetHashCode() : 0);
				result = (result * 397) ^
				         (_run != null ? _run.GetHashCode() : 0);
				result = (result * 397) ^ _tint.GetHashCode();
				return result;
			}
		}

		/// <summary>
		/// Compares two <see cref="Glyph"/> structures for equality.
		/// </summary>
		/// <param name="left">The left-hand side of the comparison.
		/// </param>
		/// <param name="right">The right-hand side of the comparison.
		/// </param>
		/// <returns><c>true</c> if equal; else <c>false</c>.</returns>
		public static bool operator ==(TextRun left, TextRun right
			)
		{
			return left.Equals(right);
		}

		/// <summary>
		/// Compares two <see cref="Glyph"/> structures for inequality.
		/// </summary>
		/// <param name="left">The left-hand side of the comparison.
		/// </param>
		/// <param name="right">The right-hand side of the comparison.
		/// </param>
		/// <returns><c>false</c> if equal; else <c>tr</c>.</returns>
		public static bool operator !=(TextRun left, TextRun right
			)
		{
			return !left.Equals(right);
		}
	}
}